package com.zbkj.service.service.monitor.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.zbkj.common.model.merchant.Merchant;
import com.zbkj.common.model.monitor.ZfbMonitorDeviceStatus;
import com.zbkj.common.model.monitor.ZfbMonitorEquipment;
import com.zbkj.common.monitorchannel.GetDeviceModelModulesV3Request;
import com.zbkj.common.monitorchannel.GetDeviceModelV3Request;
import com.zbkj.common.monitorchannel.vo.MonitorChannelEquipmentStatusVo;
import com.zbkj.common.monitorchannel.vo.MonitorSetOpenFlagVo;
import com.zbkj.service.dao.monitor.ZfbMonitorDeviceStatusDao;
import com.zbkj.service.service.MerchantService;
import com.zbkj.service.service.monitor.IZfbMonitorEquipmentService;
import com.zbkj.service.service.monitor.ZfbMonitorDeviceStatusService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 监控设备状态服务实现类
 * +----------------------------------------------------------------------
 * @author xiaolic
 * +----------------------------------------------------------------------
 */
@Slf4j
@Service
public class ZfbMonitorDeviceStatusServiceImpl extends ServiceImpl<ZfbMonitorDeviceStatusDao, ZfbMonitorDeviceStatus> implements ZfbMonitorDeviceStatusService {

    @Autowired
    private IZfbMonitorEquipmentService zfbMonitorEquipmentService;
    
    @Autowired
    private MerchantService merchantService;
    
    /**
     * 根据license和过期时间信息处理设备状态
     * @param license 设备license
     * @param expireInfo 包含过期时间和套餐类型的Map
     * @param orderNo 最近一次的订单号
     * @return 处理结果
     */
    @Override
    public boolean processDeviceStatus(String license, Map<String, Object> expireInfo, String orderNo) {
        log.info("处理设备状态，license = {}, expireInfo = {}", license, expireInfo);
        
        // 1.判断过期时间和套餐类型是否为NULL
        Date expireTime = (Date) expireInfo.get("expireTime");
        Integer mealType = (Integer) expireInfo.get("mealType");
        
        if (expireTime == null && mealType == null) {
            log.info("设备{}过期时间和套餐类型均为NULL，不进行处理", license);
            return true;
        }
        
        try {
            // 2.查询设备状态，获取did
            MonitorChannelEquipmentStatusVo equipmentStatus = zfbMonitorEquipmentService.getEquipmentStatus(license);
            if (equipmentStatus == null) {
                log.error("获取设备状态失败，license = {}", license);
                return false;
            }
            
            String did = equipmentStatus.getDid();
            if (StrUtil.isBlank(did)) {
                log.error("设备did为空，license = {}", license);
                return false;
            }
            
            // 3.调用GetDeviceModel获取摄像机状态
            GetDeviceModelV3Request request = new GetDeviceModelV3Request();
            request.setDid(did);
            GetDeviceModelModulesV3Request modelModulesV3Request = new GetDeviceModelModulesV3Request();
            modelModulesV3Request.setAIIoTID("0");
            modelModulesV3Request.setAIIoTType("1012"); // 设置AIIoTType为1012
            request.setModules(Lists.newArrayList(modelModulesV3Request));
            
            JSONObject jsonObject = zfbMonitorEquipmentService.GetDeviceModel(request, 0);
            log.info("获取设备状态结果：{}", jsonObject);
            
            // 4.解析CamStatus字段值 0-关闭，1-打开
            String camStatus = "";
            try {
                if (jsonObject != null && jsonObject.containsKey("ModelsSetting")) {
                    JSONArray modelsSetting = jsonObject.getJSONArray("ModelsSetting");
                    jsonObject = modelsSetting.getJSONObject(0);
                    if (jsonObject != null && jsonObject.containsKey("Buss")) {
                        JSONObject buss = jsonObject.getJSONObject("Buss");
                        if (buss != null && buss.containsKey("CamList")) {
                            Object camListObj = buss.get("CamList");
                            if (camListObj instanceof cn.hutool.json.JSONArray) {
                                cn.hutool.json.JSONArray camList = (cn.hutool.json.JSONArray) camListObj;
                                if (camList.size() > 0) {
                                    JSONObject camInfo = camList.getJSONObject(0);
                                    if (camInfo != null && camInfo.containsKey("CamStatus")) {
                                        camStatus = camInfo.getStr("CamStatus");
                                    }
                                }
                            }
                        }
                    }
                }

            } catch (Exception e) {
                log.error("解析摄像机状态失败，license = {}，错误: {}", license, e.getMessage(), e);
            }
            
            log.info("设备摄像机状态：license={}, camStatus={}", license, camStatus);
            
            // 5.判断设备是否过期并进行相应处理
            // 套餐类型（1=免费 2=付费）
            boolean isExpired = (expireTime != null && expireTime.before(new Date())) || (expireTime == null && mealType == 2);
            MonitorSetOpenFlagVo openFlagVo = new MonitorSetOpenFlagVo();
            openFlagVo.setLicense(license);
            openFlagVo.setDid(did);

            // 最近一次操作类型（1=开启 2=关闭）
            Integer lastOperType = null;
            // 最近一次操作结果（1=成功 2=失败）
            Integer lastOperResult = null;
            // 最近一次操作返回的错误信息
            String lastOperErrorInfo = null;
            if (!isExpired && ("0".equals(camStatus) || Objects.equals(camStatus, ""))) {
                // 未过期，且摄像机状态为关闭，需要打开
                log.info("设备未过期但摄像机处于关闭状态或摄像机状态获取失败，执行打开操作，license={}", license);
                openFlagVo.setStatus("1"); // 打开
                JSONObject result = zfbMonitorEquipmentService.v3SetOpenFlag(openFlagVo, 0);
                log.info("打开设备结果：{}", result);
                lastOperResult = 1;
                lastOperType = 1;
            } else if (isExpired && ("1".equals(camStatus) || Objects.equals(camStatus, ""))) {
                // 已过期，且摄像机状态为打开，需要关闭
                log.info("设备已过期但摄像机处于打开状态或摄像机状态获取失败，执行关闭操作，license={}", license);
                openFlagVo.setStatus("0"); // 关闭
                JSONObject result = zfbMonitorEquipmentService.v3SetOpenFlag(openFlagVo, 0);
                log.info("关闭设备结果：{}", result);
                lastOperResult = 1;
                lastOperType = 2;
            } else {
                log.info("设备状态无需变更，license={}, isExpired={}, camStatus={}", license, isExpired, camStatus);
            }
            
            // 6.记录设备的过期时间和状态
            ZfbMonitorDeviceStatus deviceStatus = getByLicense(license);
            Date now = new Date();
            
            if (deviceStatus == null) {
                // 新建记录
                deviceStatus = new ZfbMonitorDeviceStatus();
                deviceStatus.setLicense(license);
                deviceStatus.setExpireTime(expireTime);
                deviceStatus.setMealType(mealType);
                if (lastOperResult != null && lastOperResult == 1) {
                    deviceStatus.setStatus(lastOperType == 1 ? 1 : 0);
                } else {
                    deviceStatus.setStatus(new Integer(camStatus));
                }
                deviceStatus.setLastOperType(lastOperType);
                deviceStatus.setLastOperResult(lastOperResult);
                deviceStatus.setLastOperErrorInfo(lastOperErrorInfo);
                if (orderNo != null) {
                    deviceStatus.setLastOrderNo(orderNo);
                }
                deviceStatus.setCreateTime(now);
                deviceStatus.setUpdateTime(now);
                
                // 通过license获取商户ID
                try {
                    LambdaQueryWrapper<ZfbMonitorEquipment> lqw = new LambdaQueryWrapper<>();
                    lqw.eq(ZfbMonitorEquipment::getLicense, license);
                    ZfbMonitorEquipment equipment = zfbMonitorEquipmentService.getOne(lqw);
                    if (equipment != null) {
                        deviceStatus.setMerchantId(equipment.getMerchantId());
                    }
                } catch (Exception e) {
                    log.error("获取设备商户ID失败，license = {}", license, e);
                }
                
                save(deviceStatus);
            } else {
                // 更新记录
                deviceStatus.setExpireTime(expireTime);
                deviceStatus.setMealType(mealType);
                if (lastOperResult != null && lastOperResult == 1) {
                    deviceStatus.setStatus(lastOperType == 1 ? 1 : 0);
                } else {
                    deviceStatus.setStatus(new Integer(camStatus));
                }
                deviceStatus.setLastOperType(lastOperType);
                deviceStatus.setLastOperResult(lastOperResult);
                deviceStatus.setLastOperErrorInfo(lastOperErrorInfo);
                if (orderNo != null) {
                    deviceStatus.setLastOrderNo(orderNo);
                }
                deviceStatus.setUpdateTime(now);
                // 为了保证null字段也会被更新，所以采用了如下写法
                LambdaUpdateWrapper<ZfbMonitorDeviceStatus> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(ZfbMonitorDeviceStatus::getId, deviceStatus.getId())
                        .set(ZfbMonitorDeviceStatus::getExpireTime, deviceStatus.getExpireTime())
                        .set(ZfbMonitorDeviceStatus::getMealType, deviceStatus.getMealType())
                        .set(ZfbMonitorDeviceStatus::getStatus, deviceStatus.getStatus())
                        .set(ZfbMonitorDeviceStatus::getLastOperType, deviceStatus.getLastOperType())
                        .set(ZfbMonitorDeviceStatus::getLastOperResult, deviceStatus.getLastOperResult())
                        .set(ZfbMonitorDeviceStatus::getLastOperErrorInfo, deviceStatus.getLastOperErrorInfo())
                        .set(ObjectUtil.isNotNull(deviceStatus.getLastOrderNo()), ZfbMonitorDeviceStatus::getLastOrderNo, deviceStatus.getLastOrderNo())
                        .set(ZfbMonitorDeviceStatus::getUpdateTime, deviceStatus.getUpdateTime());
                update(updateWrapper);
            }
            
            return true;
        } catch (Exception e) {
            log.error("处理设备状态异常，license = {}", license, e);
            return false;
        }
    }

    /**
     * 根据商家id，更新设备状态
     * @param merId
     */
    @Override
    public void updateDeviceStatusByMerId(Integer merId) {
        Merchant merchant = merchantService.getById(merId);
        if (merchant == null) {
            return;
        }

        // 获取商户下的所有监控设备
        LambdaQueryWrapper<ZfbMonitorEquipment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ZfbMonitorEquipment::getMerchantId, merchant.getId());
        List<ZfbMonitorEquipment> equipmentList = zfbMonitorEquipmentService.list(queryWrapper);

        if (CollectionUtils.isEmpty(equipmentList)) {
            log.info("商户[{}]没有监控设备", merchant.getName());
            return;
        }

        int totalDevices = equipmentList.size();
        int processedDevices = 0;

        Date expireTime = null;
        // 监控类型 1=免费  2=付费
        if (Objects.equals(merchant.getMonitorType(), 1)) {
            expireTime = calculateMerchantExpireTime(merchant);
        }

        // 处理每个设备
        for (ZfbMonitorEquipment equipment : equipmentList) {
            try {
                // 获取设备过期信息
                ZfbMonitorDeviceStatus deviceStatus = getByLicense(equipment.getLicense());

                // 如果当前设备的套餐类型为付费且未过期，则跳过
                // mealType:套餐类型（1=免费 2=付费）
                if (ObjectUtil.isNotNull(deviceStatus)
                        && Objects.equals(deviceStatus.getMealType(), 2)
                        && deviceStatus.getExpireTime() != null) {
                    continue;
                }

                if (ObjectUtil.isNotNull(deviceStatus)) {
                    LambdaUpdateWrapper<ZfbMonitorDeviceStatus> updateWrapper = new LambdaUpdateWrapper<>();
                    updateWrapper.eq(ZfbMonitorDeviceStatus::getId, deviceStatus.getId())
                            // 监控类型 1=免费  2=付费
                            .set(ZfbMonitorDeviceStatus::getMealType, merchant.getMonitorType())
                            .set(ZfbMonitorDeviceStatus::getExpireTime, expireTime)
                            .set(ZfbMonitorDeviceStatus::getUpdateTime, new Date());
                    update(updateWrapper);
                } else {
                    ZfbMonitorDeviceStatus newDeviceStatus = new ZfbMonitorDeviceStatus();
                    newDeviceStatus.setMerchantId(merchant.getId());
                    newDeviceStatus.setLicense(equipment.getLicense());
                    newDeviceStatus.setMealType(merchant.getMonitorType());
                    newDeviceStatus.setExpireTime(expireTime);
                    // 状态（0=关闭 1=开启）
                    newDeviceStatus.setStatus(0);
                    newDeviceStatus.setCreateTime(new Date());
                    newDeviceStatus.setUpdateTime(new Date());
                    save(newDeviceStatus);
                }

                Map<String, Object> expireInfo = new HashMap<>();
                expireInfo.put("expireTime", expireTime);
                expireInfo.put("mealType", merchant.getMonitorType());

                // 处理设备状态
                boolean result = processDeviceStatus(equipment.getLicense(), expireInfo, null);
                if (result) {
                    processedDevices++;
                }
            } catch (Exception e) {
                log.error("处理设备[{}]异常", equipment.getLicense(), e);
            }
        }

        log.info("商家监控设备状态更新完成，共更新{}个设备，成功{}个", totalDevices, processedDevices);
    }

    /**
     * 根据license查询设备过期时间和套餐类型
     * @param license 设备license
     * @return 包含过期时间和套餐类型的Map，如果没有则相应的值为null
     */
    @Override
    public Map<String, Object> getExpireTimeByLicense(String license) {
        log.info("获取设备过期时间和套餐类型，license = {}", license);
        
        Map<String, Object> result = new HashMap<>();
        
        // 1. 获取设备状态表中的过期时间和套餐类型
        Date deviceExpireTime = null;
        Integer deviceMealType = null;
        ZfbMonitorDeviceStatus deviceStatus = getByLicense(license);
        if (ObjectUtil.isNotNull(deviceStatus)) {
            deviceExpireTime = deviceStatus.getExpireTime();
            deviceMealType = deviceStatus.getMealType();
        }
        
        // 2. 获取商户表中的过期时间
        Date merchantExpireTime = null;
        Integer merchantMealType = null;
        LambdaQueryWrapper<ZfbMonitorEquipment> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ZfbMonitorEquipment::getLicense, license);
        ZfbMonitorEquipment equipment = zfbMonitorEquipmentService.getOne(lqw);
        if (ObjectUtil.isNotNull(equipment) && ObjectUtil.isNotNull(equipment.getMerchantId())) {
            Merchant merchant = merchantService.getById(equipment.getMerchantId());
            if (ObjectUtil.isNotNull(merchant)) {
                merchantMealType = merchant.getMonitorType();
                // 监控类型 1=免费  2=付费
                if (Objects.equals(merchantMealType, 1) && ObjectUtil.isNotNull(merchant.getMonitorStartTime())) {
                    // 根据免费监控类型计算过期时间
                    merchantExpireTime = calculateMerchantExpireTime(merchant);
                }
            }
        }
        
        log.info("设备过期时间和套餐类型对比: "
                + "deviceExpireTime={}, deviceMealType={}, "
                + "merchantExpireTime={}, merchantMealType={}", 
                deviceExpireTime, deviceMealType, merchantExpireTime, merchantMealType);
        
        // 3. 比较两个过期时间，返回较大的那个及其对应的套餐类型
        Date finalExpireTime = null;
        Integer finalMealType = null;
        
        if (ObjectUtil.isNull(deviceExpireTime) && ObjectUtil.isNull(merchantExpireTime)
            && ObjectUtil.isNull(merchantMealType)) {
            // 两个时间都为空，返回空
            finalExpireTime = null;
            finalMealType = null;
        } else if (ObjectUtil.isNull(deviceExpireTime)) {
            // 设备时间为空，返回商户时间和套餐类型
            finalExpireTime = merchantExpireTime;
            finalMealType = merchantMealType;
        } else if (ObjectUtil.isNull(merchantExpireTime)) {
            // 商户时间为空，返回设备时间和套餐类型
            finalExpireTime = deviceExpireTime;
            finalMealType = deviceMealType;
        } else {
            // 套餐类型（1=免费 2=付费）
            // 当用户购买了付费套餐时，直接返回
            if (Objects.equals(deviceMealType, 2) && deviceExpireTime != null) {
                finalExpireTime = deviceExpireTime;
                finalMealType = deviceMealType;
            }
            // 两个时间都不为空，返回较大的时间和对应的套餐类型
            else if (deviceExpireTime.after(merchantExpireTime)) {
                finalExpireTime = deviceExpireTime;
                finalMealType = deviceMealType;
            } else {
                finalExpireTime = merchantExpireTime;
                finalMealType = merchantMealType;
            }
        }
        
        result.put("expireTime", finalExpireTime);
        result.put("mealType", finalMealType);
        
        return result;
    }
    
    /**
     * 计算商户免费套餐的过期时间
     * @param merchant 商户对象
     * @return 过期时间
     */
    private Date calculateMerchantExpireTime(Merchant merchant) {
        if (ObjectUtil.isNull(merchant.getMonitorStartTime())) {
            return null;
        }
        
        // 直接将字符串转换为LocalDateTime
        LocalDateTime startDateTime;
        try {
            // 假设时间格式为 yyyy-MM-dd HH:mm:ss
            startDateTime = LocalDateTime.parse(
                merchant.getMonitorStartTime(),
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
            );
        } catch (Exception e) {
            log.error("解析商户监控开始时间失败，monitorStartTime={}\n{}", 
                    merchant.getMonitorStartTime(), e);
            return null;
        }
        
        Integer freeMonitorTime = merchant.getFreeMonitorTime();
        
        // 判断免费时长类型（1=免费一个月 2=免费一个季度 3=免费一年 4=免费两年 5=免费三年）
        LocalDateTime endDateTime;
        switch (freeMonitorTime) {
            case 1: // 免费一个月
                endDateTime = startDateTime.plusMonths(1);
                break;
            case 2: // 免费一个季度
                endDateTime = startDateTime.plusMonths(3);
                break;
            case 3: // 免费一年
                endDateTime = startDateTime.plusYears(1);
                break;
            case 4: // 免费两年
                endDateTime = startDateTime.plusYears(2);
                break;
            case 5: // 免费三年
                endDateTime = startDateTime.plusYears(3);
                break;
            default:
                return null;
        }
        
        // 转换回Date返回
        return Date.from(endDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 更新设备状态
     * @param license 设备license
     * @param status 设备状态（0=关闭 1=开启）
     * @return 更新结果
     */
    @Override
    public boolean updateDeviceStatus(String license, Integer status) {
        ZfbMonitorDeviceStatus deviceStatus = getByLicense(license);
        if (ObjectUtil.isNull(deviceStatus)) {
            log.error("更新设备状态失败，设备不存在，license = {}", license);
            return false;
        }
        
        deviceStatus.setStatus(status);
        deviceStatus.setUpdateTime(new Date());
        return updateById(deviceStatus);
    }

    /**
     * 根据license获取设备状态信息
     * @param license 设备license
     * @return 设备状态对象
     */
    @Override
    public ZfbMonitorDeviceStatus getByLicense(String license) {
        LambdaQueryWrapper<ZfbMonitorDeviceStatus> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ZfbMonitorDeviceStatus::getLicense, license);
        return getOne(lqw);
    }
}
